﻿using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Auditing;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.ObjectMapping;
using Abp.Runtime.Validation;
using Abp.UI;
using CPPProject.CPP.Dto;
using CPPProject.Redis;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace CPPProject.CPP
{
    public class CPPAttachmentAppService : AsyncCrudAppService<CPPAttachment, CPPAttachmentDto, Guid, PagedResultRequestDto, CreateCPPAttachmentDto, UpdateCPPAttachmentDto>, ICPPAttachmentAppService
    {
        private readonly IObjectMapper _objectMapper;
        private readonly IDatabase _db;
        public CPPAttachmentAppService(
            IRepository<CPPAttachment, Guid> repository, 
            IObjectMapper objectMapper,
            RedisService redis) : base(repository)
        {
            _objectMapper = objectMapper;
            _db = redis.GetDatabase(8);
        }

        public async Task<byte[]> GetFileAsync(string id)
        {
            var resp = await Repository.GetAll().Where(o => o.Id.ToString() == id).ToListAsync();
            if (resp != null)
            {
                var file = resp.FirstOrDefault();
                if (file != null)
                {
                    if (_db != null)
                        _db.StringSet(file.Id.ToString(), file.FileData);
                    return file.FileData;
                }
                else
                    return null;
            }
            else
                return null;
        }
        [AbpAuthorize]
        public async Task<string> UploadFiles(
            IFormFile[] files,
            string objectId = "",
            string objectName = "",
            string objectField = "")
        {
            string[] filenames = new string[files.Length];
            int i = 0;
            foreach (var formFile in files)
            {
                if (formFile.Length > 0)
                {
                    string fileExt = Path.GetExtension(formFile.FileName);
                    long fileSize = formFile.Length;
                    //string newName = Guid.NewGuid().ToString() + fileExt;

                    Stream stream = formFile.OpenReadStream();
                    byte[] bytes = new byte[stream.Length];
                    await stream.ReadAsync(bytes, 0, bytes.Length);
                    var resp = Repository.Insert(new CPPAttachment()
                    {
                        TenantId = AbpSession.TenantId == null || AbpSession.TenantId == 0 ? 1 : AbpSession.TenantId.Value,
                        FileName = formFile.FileName,
                        FileExtension = fileExt,
                        FileSize = fileSize,
                        FileData = bytes,
                        ObjectId = objectId,
                        ObjectName = objectName,
                        ObjectField = objectField,
                    });
                    stream.Close();
                    filenames[i] = resp.Id.ToString();                    
                }
                i++;
            }
            return string.Join(",", filenames);
        }

        [DisableValidation]
        [DisableAuditing]
        public async Task<PagedResultDto<CPPAttachmentDto>> GetList(int skipCount = 0, int maxResultCount = 10, string keywords = "", string ext = "")
        {
            PagedResultDto<CPPAttachmentDto> resultDto = new PagedResultDto<CPPAttachmentDto>();
            List<CPPAttachmentDto> lists = new List<CPPAttachmentDto>();
            Expression<Func<CPPAttachment, bool>> expr = null;
            if (!string.IsNullOrEmpty(keywords))
            {
                expr = expr == null ? o => o.FileName.Contains(keywords) : expr.ExpressionAnd(o => o.FileName.Contains(keywords));
            }
            if (!string.IsNullOrEmpty(ext))
            {
                expr = expr == null ? o => o.FileExtension == ext : expr.ExpressionAnd(o => o.FileExtension == ext);
            }
            if (expr != null)
            {
                lists = await Repository.GetAll().Where(expr).Select(m => new CPPAttachmentDto
                {
                    FileExtension = m.FileExtension,
                    FileSize = m.FileSize,
                    CreationTime = m.CreationTime,
                    Id = m.Id,
                    ObjectId = m.ObjectId,
                    FileName = m.FileName,
                    ObjectName = m.ObjectName
                }).ToListAsync();
            }
            else
            {
                lists = await Repository.GetAll().Select(m => new CPPAttachmentDto
                {
                    FileExtension = m.FileExtension,
                    FileSize = m.FileSize,
                    CreationTime = m.CreationTime,
                    Id = m.Id,
                    ObjectId = m.ObjectId,
                    FileName = m.FileName,
                    ObjectName = m.ObjectName
                }).ToListAsync();
            }
            lists = lists.OrderByDescending(o => o.CreationTime).ToList();
            var dtos = lists.Skip(skipCount).Take(maxResultCount).ToList();
            resultDto.Items = _objectMapper.Map<List<CPPAttachmentDto>>(dtos);
            resultDto.TotalCount = lists.Count;

            return resultDto;
        }
        public byte[] GetFileCache(string key)
        {
            return _db != null ? _db.StringGet(key) : RedisValue.Null;
        }
    }
}
